//
// Created by sxt on 2023/10/18.
//

#ifndef MY_REFLECT_TYPE_DESCRIPTOR_H
#define MY_REFLECT_TYPE_DESCRIPTOR_H

#include <string>
#include <any>
#include <vector>
#include <Field.h>
#include <Method.h>

namespace myreflect {

    using namespace std;

    class RawTypeDescriptorBuilder;

    /**
     * 类型描述符
     */
    class TypeDescriptor {

        // 声明RawTypeDescriptorBuilder为友元 供该类访问本类的私有成员
        friend class RawTypeDescriptorBuilder;

    public:
        /**
         * 获取类名
         * @return 类名
         */
        [[nodiscard]] const string &getClassName() const;

        /**
         * 获取类中声明的所有属性集合
         * @return 类中声明的所有属性集合
         */
        [[nodiscard]] const vector<Field> &getDeclaredFields() const;

        /**
         * 获取类中声明的所有方法集合
         * @return 类中声明的所有方法集合
         */
        [[nodiscard]] const vector<Method> &getDeclaredMethods() const;

        /**
         * 根据属性名获取对应属性
         * 获取不到抛出异常
         * @param name 属性名
         * @return 属性
         */
        [[nodiscard]] Field getField(const string &name) const;

        /**
         * 根据方法名获取对应方法
         *  获取不到抛出异常
         * @param name 方法名
         * @return 方法
         */
        [[nodiscard]] Method getMethod(const string &name) const;

        /**
         * 对象创建
         * @return 创建后的任意对象指针
         */
        void * newInstance();

    private:
        /**
         * 类名
         */
        string className;

        /**
         * 所有属性集合
         */
        vector<Field> fields;

        /**
         * 方法集合
         */
        vector<Method> methods;

        /**
         * 用于保存对象创建方法的函数
         */
        function<void *()> createObjMethod{nullptr};
    };

    /**
     * 类型描述符构builder
     */
    class RawTypeDescriptorBuilder {
    public:
        explicit RawTypeDescriptorBuilder(const string &name, void *(createObj)());

        RawTypeDescriptorBuilder(const RawTypeDescriptorBuilder &) = delete;

        RawTypeDescriptorBuilder &operator=(const RawTypeDescriptorBuilder &) = delete;

        ~RawTypeDescriptorBuilder();

    public:
        /**
         * 添加属性
         * @tparam Class 对应类
         * @tparam Type 对应类中的某个属性类型
         * @param name 属性名
         * @param var 对应类中的某个属性的指针
         */
        template<class Class, typename Type>
        void addField(const string &name, Type Class::*var) {
            Field field{var};
            field.fieldName = name;
            typeDescriptor->fields.push_back(std::move(field));
        }

        /**
         * 添加方法
         * @tparam Class 对应类
         * @tparam Type 对应类中的某个方法类型
         * @param name 方法名
         * @param var 对应类中的某个方法的指针
         */
        template<class Class, typename Type>
        void addMethod(const string &name, Type Class::*var) {
            Method method{var};
            method.methodName = name;
            typeDescriptor->methods.push_back(std::move(method));
        }

    private:
        /**
         * 实例化的类型描述符唯一指针
         */
        unique_ptr<TypeDescriptor> typeDescriptor{nullptr};
    };


    template<typename Class>
    class TypeDescriptorBuilder {

    public:
        TypeDescriptorBuilder(const string &name, void *(createObj)()) : rawTypeDescriptorBuilder(name, createObj) {
        }

    public:
        template<typename Type>
        TypeDescriptorBuilder &addField(const string &name, Type Class::*var) {
            rawTypeDescriptorBuilder.addField(name, var);
            return *this;
        }

        template<typename Type>
        TypeDescriptorBuilder &addMethod(const string &name, Type Class::*var) {
            rawTypeDescriptorBuilder.addMethod(name, var);
            return *this;
        }

    private:
        RawTypeDescriptorBuilder rawTypeDescriptorBuilder;
    };

    /**
     * 类型描述符注册器
     */
    class Registry {

    public:
        static Registry &instance();

    public:
        /**
         * 注册类型描述符
         * @param typeDesc 类型描述符
         */
        void registerClass(unique_ptr<TypeDescriptor> typeDesc);

        /**
         * 根据类名查找对应的类型描述符
         * @param name 类名
         * @return 类型描述符
         */
        TypeDescriptor *findClass(const string &name);

    private:
        /**
         * 类型描述符集合
         */
        unordered_map<string, unique_ptr<TypeDescriptor>> typeMaps;
    };


    /**
     * 注册类
     * @tparam T 类型
     * @param name 类名
     * @param createObj 对象创建方法
     * @return 类型描述符构建器
     */
    template<typename T>
    TypeDescriptorBuilder<T> addClass(const string &name, void *(createObj)()) {
        return TypeDescriptorBuilder<T>(name, createObj);
    }

    /**
     * 根据类名获取对应的类型描述符
     * @param name 类名
     * @return 类型描述符
     */
    TypeDescriptor &getClassByName(const string &name);

#define REGISTER_CLASS(className) \
    auto typeDescriptorBuilder = myreflect::addClass<className>(#className, []()-> void * {return (void *)(new className());}); \
    typeDescriptorBuilder

}


#endif //MY_REFLECT_TYPE_DESCRIPTOR_H
